package com.eight.paper.admin.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.DocumentRenderData;
import com.deepoove.poi.data.Documents;
import com.deepoove.poi.util.PoitlIOUtils;
import com.eight.common.config.EightConfig;
import com.eight.common.constant.ExamConstants;
import com.eight.common.core.domain.entity.QuestionRepo;
import com.eight.common.core.redis.RedisCache;
import com.eight.common.exception.ServiceException;
import com.eight.common.utils.*;
import com.eight.common.utils.bean.BeanUtils;
import com.eight.common.utils.poi.ExcelUtil;
import com.eight.paper.admin.domain.QuestionBase;
import com.eight.paper.admin.domain.QuestionVersion;
import com.eight.paper.admin.domain.model.*;
import com.eight.paper.admin.domain.model.enums.AnswerShowTypeEnum;
import com.eight.paper.admin.domain.model.enums.ImportQuestionTypeEnum;
import com.eight.paper.admin.domain.model.enums.QuestionSourceEnum;
import com.eight.paper.admin.domain.model.enums.QuestionTypeEnum;
import com.eight.paper.admin.mapper.QuestionBaseMapper;
import com.eight.paper.admin.mapper.QuestionRepoMapper;
import com.eight.paper.admin.mapper.QuestionVersionMapper;
import com.eight.paper.admin.service.IQuestionBaseService;
import com.eight.paper.admin.util.PdfUtil;
import com.eight.paper.admin.util.PoitlUtil;
import com.eight.paper.admin.util.pdf.PdfFreemarkerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.eight.paper.admin.domain.model.enums.QuestionTypeEnum.*;

/**
 * 试题管理Service业务层处理
 * 
 * @author 爱考线上考试系统
 * @date 2023-10-04
 */
@Service
public class QuestionBaseServiceImpl implements IQuestionBaseService 
{
    private static final Logger log = LoggerFactory.getLogger(QuestionBaseServiceImpl.class);
    @Autowired
    private QuestionBaseMapper questionBaseMapper;
    @Autowired
    private QuestionVersionMapper questionVersionMapper;
    @Autowired
    private QuestionRepoMapper questionRepoMapper;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private RedisCache redisCache;

    /**
     * 查询试题管理
     * 
     * @param id 试题管理主键
     * @return 试题管理
     */
    @Override
    public QuestionBase selectQuestionBaseById(Integer id)
    {
        return questionBaseMapper.selectQuestionBaseById(id);
    }

    /**
     * 获取试题信息
     *
     * @param id 试题管理主键
     * @return 试题信息
     */
    @Override
    public QuestionBase selectQuestionBodyById(Integer id) {
        return selectQuestionBodyById(id,null, AnswerShowTypeEnum.True.getCode());
    }

    /**
     * 返回带分数的试题详情
     * @param id 试题管理主键
     * @param score 分数
     * @param type 1 显示答案，2隐藏答案
     * @return
     */
    @Override
    public QuestionBase selectQuestionBodyById(Integer id,BigDecimal score,String type) {
        return selectQuestionBody(id,score,type,null,null);
    }


    /**
     * 返回带分数的试题详情
     * @param id 试题管理主键
     * @param score
     * @param type 1 显示答案，0隐藏答案
     * @return
     */
    @Override
    public QuestionBase selectQuestionBody(Integer id, BigDecimal score, String type, Integer versionId, Integer paperQuestionId) {
        QuestionBase questionBase=  questionBaseMapper.selectQuestionBaseById(id);
        if(questionBase==null){
            throw new ServiceException("获取试题信息异常");
        }
       return selectQuestionBody(questionBase,score,type,versionId,paperQuestionId,"");
    }

    /**
     * 获取带小题分数的试题
     * @param id 试题管理主键
     * @param score
     * @param type
     * @param versionId
     * @param paperQuestionId
     * @param subScores
     * @return
     */
    @Override
    public QuestionBase selectQuestionBody(Integer id, BigDecimal score, String type, Integer versionId, Integer paperQuestionId,String subScores){
        QuestionBase questionBase=  questionBaseMapper.selectQuestionBaseById(id);
        if(questionBase==null){
            throw new ServiceException("获取试题信息异常");
        }
        return selectQuestionBody(questionBase,score,type,versionId,paperQuestionId,subScores);
    }


    /**
     * 返回带分数的试题详情
     * @param questionBase 试题基础信息
     * @param score
     * @param type 1 显示答案，0隐藏答案
     * @return
     */
    @Override
    public QuestionBase selectQuestionBody(QuestionBase questionBase,BigDecimal score,String type,Integer versionId,Integer paperQuestionId,String subScores) {
        if(questionBase==null){
            throw new ServiceException("获取试题信息异常");
        }
        QuestionVersion version = null;
        if(StringUtils.isBlank(subScores)){
            subScores = "";
        }
        String finalSubScores = subScores;
        String[] scores = subScores.replace("[", "").replace("]", "").split(",");
        if(versionId==null) {
            QuestionVersion query = new QuestionVersion();
            query.setBaseId(questionBase.getId());
            query.setVersionNo(questionBase.getVersionNo());
            version = questionVersionMapper.selectQuestionVersionList(query).stream().findFirst().orElse(null);
        }else {
            version = questionVersionMapper.selectQuestionVersionById(versionId);
        }
        if (version == null) {
            System.out.println("-------------------->"+questionBase.getId());
            throw new ServiceException("获取试题信息异常");
        }
        String questionType=questionBase.getQuestionType();
        if(SingleChoice.getCode().equals(questionType)||MultipleChoice.getCode().equals(questionType)||IMAGE.getCode().equals(questionType)) {
            QuestionChoiceBody body= JSONObject.parseObject(version.getContent(), QuestionChoiceBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores(subScores);
            body.setPaperQuestionId(paperQuestionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getOptions().stream().forEach(option -> {
                    option.setAnswerFlag(false);
                });
                body.setExplain("");
            }
            return body;
        }else if(GapFilling.getCode().equals(questionType)||Explain.getCode().equals(questionType)||ShortAnswer.getCode().equals(questionType)||Analysis.getCode().equals(questionType)||Discuss.getCode().equals(questionType)) {
            QuestionAnswerBody body= JSONObject.parseObject(version.getContent(), QuestionAnswerBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores(subScores);
            body.setPaperQuestionId(paperQuestionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getAnswers().forEach(answer -> {
                    answer.setAnswer("");
                });
                body.setExplain("");
            }
            AtomicInteger index = new AtomicInteger();
            body.getAnswers().forEach(answer -> {
                if(StringUtils.isNotBlank(finalSubScores)) {
                    if (scores.length > index.intValue()) {
                        String subScore = scores[index.getAndIncrement()];
                        System.out.println("----------------->" + subScore);
                        if (StringUtils.isNotBlank(subScore)) {
                            answer.setScore(new BigDecimal(subScore));
                        } else {
                            answer.setScore(BigDecimal.ZERO);
                        }
                    }
                }else {
                    answer.setScore(getSubQuestionScoreByDivide(score,body.getAnswers().size()));
                }
            });
            return body;
        }else if(B1.getCode().equals(questionType)){
            QuestionB1Body body= JSONObject.parseObject(version.getContent(), QuestionB1Body.class);
            body.setVersionId(version.getId());
            BeanUtils.copyProperties(questionBase, body);
            body.setScore(score);
            body.setSubScores(subScores);
            body.setPaperQuestionId(paperQuestionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getChoices().forEach(choice -> {
                    choice.setAnswer("");
                    choice.setExplain("");
                });
            }
            AtomicInteger index = new AtomicInteger();
            body.getChoices().forEach(choice -> {
                if(StringUtils.isNotBlank(finalSubScores)) {
                    if (scores.length > index.intValue()) {
                        String subScore = scores[index.getAndIncrement()];
                        System.out.println("----------------->" + subScore);
                        if (StringUtils.isNotBlank(subScore)) {
                            choice.setScore(new BigDecimal(subScore));
                        } else {
                            choice.setScore(BigDecimal.ZERO);
                        }
                    }
                }else{
                    choice.setScore(getSubQuestionScoreByDivide(score,body.getChoices().size()));
                }
            });
            return body;
        }else if(A3A4Single.getCode().equals(questionType)||A3A4Multiple.getCode().equals(questionType)){
            QuestionA3A4Body body= JSONObject.parseObject(version.getContent(), QuestionA3A4Body.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores(subScores);
            body.setPaperQuestionId(paperQuestionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getQuestions().forEach(question -> {
                    question.setExplain("");
                    question.getOptions().forEach(option ->{
                        option.setAnswerFlag(false);
                    } );
                });
            }
            AtomicInteger index = new AtomicInteger();
            body.getQuestions().forEach(question -> {
                if(StringUtils.isNotBlank(finalSubScores)) {
                    if (scores.length > index.intValue()) {
                        String subScore = scores[index.getAndIncrement()];
                        System.out.println("----------------->" + subScore);
                        if (StringUtils.isNotBlank(subScore)) {
                            question.setScore(new BigDecimal(subScore));
                        } else {
                            question.setScore(BigDecimal.ZERO);
                        }
                    }
                }else{
                    question.setScore(getSubQuestionScoreByDivide(score,body.getQuestions().size()));
                }
            });
            return body;
        }else if(TrueFalse.getCode().equals(questionType)){
            QuestionTFBody body= JSONObject.parseObject(version.getContent(), QuestionTFBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores(subScores);
            body.setPaperQuestionId(paperQuestionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.setAnswerFlag("");
                body.setExplain("");
            }
            return body;
        }else {
            throw new ServiceException("获取试题信息异常");
        }
    }

    /**
     * 获取B1、A3A4题型每小题分值，按照平均计算
     * @return
     */
    private BigDecimal getSubQuestionScoreByDivide(BigDecimal score, Integer  questionCount){
        if(!StringUtils.isNull(score)){
            return new BigDecimal(Arith.div(score.doubleValue(), questionCount, 1));
        }else {
            return BigDecimal.ZERO;
        }
    }

    /**
     * 根据版本表数据获取试题信息
     * @param baseId
     * @param score
     * @param type
     * @param version
     * @param questionVersionId
     * @return
     */
    @Override
    public QuestionBase selectQuestionBodyFromVersion(Integer baseId,BigDecimal score,String type,QuestionVersion version,Integer questionVersionId) {
        QuestionBase questionBase=  questionBaseMapper.selectQuestionBaseById(baseId);
        if(questionBase==null){
            throw new ServiceException("获取试题信息异常");
        }
        if (version == null) {
            System.out.println("-------------------->"+questionBase.getId());
            throw new ServiceException("获取试题信息异常");
        }
        String questionType=questionBase.getQuestionType();
        if(SingleChoice.getCode().equals(questionType)||MultipleChoice.getCode().equals(questionType)||IMAGE.getCode().equals(questionType)) {
            QuestionChoiceBody body= JSONObject.parseObject(version.getContent(), QuestionChoiceBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores("");
            body.setPaperQuestionId(questionVersionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getOptions().stream().forEach(option -> {
                    option.setAnswerFlag(false);
                });
                body.setExplain("");
            }
            return body;
        }else if(GapFilling.getCode().equals(questionType)||Explain.getCode().equals(questionType)||ShortAnswer.getCode().equals(questionType)||Analysis.getCode().equals(questionType)||Discuss.getCode().equals(questionType)) {
            QuestionAnswerBody body= JSONObject.parseObject(version.getContent(), QuestionAnswerBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores("");
            body.setPaperQuestionId(questionVersionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getAnswers().forEach(answer -> {
                    answer.setAnswer("");
                });
                body.setExplain("");
            }
            body.getAnswers().forEach(answer -> {
                answer.setScore(getSubQuestionScoreByDivide(score,body.getAnswers().size()));
            });
            return body;
        }else if(B1.getCode().equals(questionType)){
            QuestionB1Body body= JSONObject.parseObject(version.getContent(), QuestionB1Body.class);
            body.setVersionId(version.getId());
            BeanUtils.copyProperties(questionBase, body);
            body.setScore(score);
            body.setSubScores("");
            body.setPaperQuestionId(questionVersionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getChoices().forEach(choice -> {
                    choice.setAnswer("");
                    choice.setExplain("");
                });
            }
            body.getChoices().forEach(choice -> {
                choice.setScore(getSubQuestionScoreByDivide(score,body.getChoices().size()));
            });
            return body;
        }else if(A3A4Single.getCode().equals(questionType)||A3A4Multiple.getCode().equals(questionType)){
            QuestionA3A4Body body= JSONObject.parseObject(version.getContent(), QuestionA3A4Body.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores("");
            body.setPaperQuestionId(questionVersionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.getQuestions().forEach(question -> {
                    question.setExplain("");
                    question.getOptions().forEach(option ->{
                        option.setAnswerFlag(false);
                    } );
                });
            }
            body.getQuestions().forEach(question -> {
                question.setScore(getSubQuestionScoreByDivide(score,body.getQuestions().size()));
            });
            return body;
        }else if(TrueFalse.getCode().equals(questionType)){
            QuestionTFBody body= JSONObject.parseObject(version.getContent(), QuestionTFBody.class);
            BeanUtils.copyProperties(questionBase, body);
            body.setVersionId(version.getId());
            body.setScore(score);
            body.setSubScores("");
            body.setPaperQuestionId(questionVersionId);
            if(AnswerShowTypeEnum.False.getCode().equals(type)) {
                body.setAnswerFlag("");
                body.setExplain("");
            }
            return body;
        }else {
            throw new ServiceException("获取试题信息异常");
        }
    }

    /**
     * 查询试题管理列表
     * 
     * @param questionBase 试题管理
     * @return 试题管理
     */
    @Override
    public List<QuestionListBody> selectQuestionBaseList(QuestionListBody questionBase)
    {
        return questionBaseMapper.selectQuestionBaseList(questionBase);
    }

    /**
     * 新增试题管理
     * 
     * @param questionBase 试题管理
     * @return 结果
     */
    @Override
    public int insertQuestionBase(QuestionBase questionBase)
    {
        questionBase.setVersionNo(1);
        questionBase.setRepoId(1);
        questionBase.setCreateTime(DateUtils.getNowDate());
        questionBase.setUpdateTime(DateUtils.getNowDate());
        return questionBaseMapper.insertQuestionBase(questionBase);
    }

    /**
     * 修改试题管理
     *
     * @param questionBase 试题管理
     * @return 结果
     */
    @Override
    public int updateQuestionBase(QuestionBase questionBase)
    {
        QuestionVersion query=new QuestionVersion();
        query.setBaseId(questionBase.getId());
        questionBase.setVersionNo(questionBase.getVersionNo()+1);
        questionBase.setUpdateTime(DateUtils.getNowDate());
        questionBase.setUpdateBy("1");
        return questionBaseMapper.updateQuestionBase(questionBase);
    }

    /**
     * 编辑试题，新增、修改
     * @param questionBase
     * @param title
     * @param content
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int editQuestion(QuestionBase questionBase,String title,String content) {
        if(questionBase.getId()==null) {
            questionBase.setCreateBy(SecurityUtils.getUserId()+"");
            questionBase.setUpdateBy(SecurityUtils.getUserId()+"");
            questionBase.setDeptId(SecurityUtils.getDeptId().intValue());
            insertQuestionBase(questionBase);
            insertQuestionVersion(questionBase, title, content);
            return questionBase.getId();
        }else {
            updateQuestionBase(questionBase);
            insertQuestionVersion(questionBase, title, content);
            return questionBase.getId();
        }
    }

    /**
     * 写入
     *
     * @param questionBase
     * @return
     */
    public Integer insertQuestionVersion(QuestionBase questionBase,String title,String content) {
        checkQuestion(questionBase,content);
        QuestionVersion questionVersion = new QuestionVersion();
        questionVersion.setDeptId(questionBase.getDeptId());
        questionVersion.setBaseId(questionBase.getId());
        questionVersion.setVersionNo(StringUtils.isNull(questionBase.getVersionNo()) ? 1 : questionBase.getVersionNo());
        questionVersion.setContent(content);
        questionVersion.setCreateBy(questionBase.getCreateBy());
        questionVersion.setTitle(title);
        questionVersion.setInnerText(ToolUtils.delHTMLTag(title));
        questionVersion.setCreateTime(new Date());
        questionVersionMapper.insertQuestionVersion(questionVersion);
        return questionBase.getVersionNo();
    }

    /**
     * 校验题目是否重复
     * @param questionBase
     * @param content
     */
    public void checkQuestion(QuestionBase questionBase,String content){
        QuestionVersion query = new QuestionVersion();
        query.setContent(content);
        query.setDeptId(questionBase.getDeptId());
        Integer countAll=questionVersionMapper.selectQuestionVersionList(query).size();
        query.setBaseId(questionBase.getId());
        Integer count=questionVersionMapper.selectQuestionVersionList(query).size();
        if(countAll>0&&countAll>count){
            throw new ServiceException("题目重复");
        }
    }

    /**
     * 批量删除试题管理
     * 
     * @param ids 需要删除的试题管理主键
     * @return 结果
     */
    @Override
    public int deleteQuestionBaseByIds(Integer[] ids)
    {
        return questionBaseMapper.deleteQuestionBaseByIds(ids);
    }

    /**
     * 删除试题管理信息
     * 
     * @param id 试题管理主键
     * @return 结果
     */
    @Override
    public int deleteQuestionBaseById(Integer id)
    {
        return questionBaseMapper.deleteQuestionBaseById(id);
    }

    /**
     * 导入试题
     * @param questions 试题列表
     * @param uuid 导入业务流水号
     * @param userId 操作用户id
     * @param deptId 操作用户部门id
     * @param repoIdMap 章节id信息
     */
    @Override
    public void importQuestions(List<QuestionTemplate> questions, String uuid, Long userId,Long deptId,HashMap<String,Integer> repoIdMap) {
        if (StringUtils.isNull(questions) || questions.size() == 0) {
            throw new ServiceException("请检查导入文件，未读取到题目！");
        }
        AtomicInteger successAmount = new AtomicInteger();
        int[] array = IntStream.range(0, questions.size())
                .filter(i -> (StringUtils.isNotEmpty(questions.get(i).getQuestionType())&&questions.get(i).getQuestionType().length()>2&&ExamConstants.QUESTIONTYPE_NAMES.contains(questions.get(i).getQuestionType().trim()))).toArray();
        redisCache.setCacheObject(String.format(ExamConstants.QUESTION_IMPORT_SUCCESS_AMOUNT,uuid), 0);
        redisCache.setCacheObject(String.format(ExamConstants.QUESTION_IMPORT_PRESET_AMOUNT,uuid), array.length);
        for(int i=0;i<array.length;i++){
            int fromIndex = array[i];
            int toIndex = i<array.length-1?array[i+1]:questions.size();
            List<QuestionTemplate> templates = questions.subList(fromIndex,toIndex);
            threadPoolTaskExecutor.execute(() -> {
                try {
                    resolveQuestionTemplate(templates, userId, deptId,repoIdMap);
                    redisCache.setCacheObject(String.format(ExamConstants.QUESTION_IMPORT_SUCCESS_AMOUNT,uuid), successAmount.incrementAndGet());
                }catch (Exception e){
                    String errLine = String.format("导入错误发生在第%s行:",fromIndex+2);
                    log.error(errLine, e);
                    String failInfo =  errLine + e.getMessage();
                    redisCache.setCacheLeftPush(String.format(ExamConstants.QUESTION_IMPORT_FAIL_INFO,uuid), failInfo);
                }
            });
        }
    }

    /**
     * 试题导入进度监测
     * @param uuid 导入业务流水号
     * @return
     */
    @Override
    public MonitorResult importMonitor(String uuid) {
        MonitorResult result = new MonitorResult();
        int failAmount = 0;
        int successAmount = 0;
        int presetAmount = 0;
        if (redisCache.hasKey(String.format(ExamConstants.QUESTION_IMPORT_PRESET_AMOUNT,uuid))) {
            presetAmount = redisCache.getCacheObject(String.format(ExamConstants.QUESTION_IMPORT_PRESET_AMOUNT,uuid));
            if (presetAmount <0) {
                result.setStatus("0");
                result.setResult("试题加载中");
            }
        } else {
            throw new ServiceException("导入处理流水号不存在！");
        }

        List<String> failInfoList = redisCache.getCacheList(String.format(ExamConstants.QUESTION_IMPORT_FAIL_INFO,uuid));
        if (redisCache.hasKey(String.format(ExamConstants.QUESTION_IMPORT_SUCCESS_AMOUNT,uuid))) {
            successAmount = redisCache.getCacheObject(String.format(ExamConstants.QUESTION_IMPORT_SUCCESS_AMOUNT,uuid));;
        }

        StringBuilder importInfo = new StringBuilder();
        if (failInfoList != null) {
            failAmount = failInfoList.size();
            int i = failAmount;
            for (String failInfo : failInfoList) {
                importInfo.insert(0, String.format("<br/>%s、%s",i--, failInfo));
            }
        }
        int currentAmount = failAmount + successAmount;
        if (failAmount > 0) {
            importInfo.insert(0, String.format("导入失败%s条数据，错误如下：",failAmount));
        }
        if (currentAmount == presetAmount) {
            result.setStatus("1");
            if(successAmount==presetAmount) {
                importInfo.insert(0, String.format("恭喜您，数据已全部导入成功！共%s条。", presetAmount));
            }else {
                importInfo.insert(0,  String.format("导入结束，共%s条，导入成功%s条。<br/>",presetAmount,successAmount));
            }
        } else {
            result.setStatus("0");
            importInfo.insert(0,  String.format("导入中，共%s条，已处理%s条,导入成功%s条。<br/>",presetAmount,currentAmount,successAmount));
        }
        result.setResult(importInfo.toString());
        return result;
    }

    /**
     * 校验题库章节名称，重复、不存在则抛出异常
     * @param questions
     * @return 返回章节名称和repoId对应关系
     */
    @Override
    public HashMap<String, Integer> validateRepoName(List<QuestionTemplate> questions) {
        HashMap<String, Integer> repoIdMap =new HashMap<>();
        Set<String> uniqueRepoNames = questions.stream().filter(t->StringUtils.isNotBlank(t.getRepoName())).map(t->t.getRepoName().trim()).collect(Collectors.toSet());
        if(uniqueRepoNames.size()==0){
            throw new ServiceException(String.format("题库章节数据异常，导入失败：%s","题库章节未维护。"));
        }
        StringBuilder validateResult = new StringBuilder();
        for(String repoName:uniqueRepoNames){
            if(!repoName.contains("/")){
                List<QuestionRepo> list = questionRepoMapper.selectQuestionRepoListByRepoName(repoName);
                if(list.size()==0){
                    validateResult.append(repoName+"不存在<br/>");
                }else if(list.size()==1){
                    repoIdMap.put(repoName,list.get(0).getRepoId().intValue());
                }else{
                    validateResult.append("'"+repoName+"'重复,请在以下全称中选择所需要的：");
                    String fullRepoNames = "";
                    for(QuestionRepo repo:list){
                        String fullRepoName = questionRepoMapper.selectFullRepoName(repo.getAncestors());
                        fullRepoNames = fullRepoNames.length()==0?fullRepoName:fullRepoNames+"、"+fullRepoName;
                        fullRepoNames +="/"+repoName;
                    }
                    validateResult.append(fullRepoNames+"<br/>");
                }
            }else {
                String sectionName = repoName.substring(repoName.lastIndexOf("/")+1,repoName.length());
                List<QuestionRepo> list = questionRepoMapper.selectQuestionRepoListByRepoName(sectionName);
                if(list.size()==0){
                    validateResult.append("'"+repoName+"'不存在<br/>");
                }else{
                    boolean existFlag = false;
                    for(QuestionRepo repo:list){
                        String fullRepoName = questionRepoMapper.selectFullRepoName(repo.getAncestors());
                        fullRepoName = fullRepoName+"/"+sectionName;
                        if(repoName.equals(fullRepoName)){
                            repoIdMap.put(repoName,list.get(0).getRepoId().intValue());
                            existFlag = !existFlag;
                            break;
                        }
                    }
                    if(!existFlag){
                        validateResult.append("'"+repoName+"'不存在<br/>");
                    }
                }
            }
        }
        if(validateResult.length()>0){
            throw new ServiceException(String.format("题库章节数据异常，导入失败：%s",validateResult));
        }
        return repoIdMap;
    }

    /**
     * 导出试题
     * @param response
     * @param type 1-excel,2-word,3-pdf
     * @param ids
     */
    @Override
    public void exportQuestion(HttpServletResponse response, String type, Integer[] ids) {
        List<QuestionBase> questions = questionBaseMapper.selectQuestionBaseListByIds(ids);
        List<QuestionTemplate> templates = buildQuestionTemplate(questions,QuestionSourceEnum.DB);
        if("1".equals(type)) {
            ExcelUtil<QuestionTemplate> util = new ExcelUtil<QuestionTemplate>(QuestionTemplate.class);
            util.exportExcel(response, templates, "试题信息");
        }
        if("2".equals(type)) {
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition","attachment;filename=\""+"questions.docx"+"\"");
            try {
                createWord(response,templates);
            } catch (Exception e) {
                log.error("导出word试题失败：" + e.getMessage(), e);
                throw new ServiceException("导出word试题失败");
            }
        }
        if("3".equals(type)) {
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition","attachment;filename=\""+"questions.pdf"+"\"");
            try {
                createPdf(response,templates);
            } catch (Exception e) {
                log.error("导出pdf试题失败：" + e.getMessage(), e);
                throw new ServiceException("导出pdf试题失败");
            }
        }
    }

    /**
     * 根据试题信息构建导出模板
     * @param questions
     * @param questionSource 获取试题来源
     * @return
     */
    @Override
    public List<QuestionTemplate> buildQuestionTemplate(List<QuestionBase> questions, QuestionSourceEnum questionSource){
        List<QuestionTemplate> list = new ArrayList<>();
        List<Future> futures = new ArrayList<>();
        int size = ExamConstants.QUESTION_EXPORT_SIZE;
        BigDecimal count = BigDecimal.valueOf(questions.size()).divide(BigDecimal.valueOf(size),0,RoundingMode.UP);
        int m = count.intValue();
        for (int i = 0; i < m; i++) {
            List<QuestionBase> questionBases;
            int current = i * size;
            if ((i + 1) == m) {
                questionBases = questions.subList(current, questions.size());
            } else {
                questionBases = questions.subList(current, current + size);
            }
            if (questionBases.size() > 0) {
                Future<List<QuestionTemplate>> submit = threadPoolTaskExecutor.submit(new Callable<List<QuestionTemplate>>() {
                    @Override
                    public List<QuestionTemplate> call() throws Exception {
                        List<QuestionTemplate> result = getQuestionTemplates(questionBases,questionSource);
                        return result;
                    }
                });
                futures.add(submit);
            }
        }
        try {
            for (Future future : futures) {
                if(future!=null) {
                    List<QuestionTemplate> result = (List<QuestionTemplate>) future.get();
                    if (result.size() > 0) {
                        list.addAll(result);
                    }
                }
            }
        } catch (Exception e) {
            log.error("导出试题异常", e);
        }
        return list;
    }

    /**
     * 根据试题获取导出模板信息
     * @param questionBases
     * @param questionSource
     * @return
     */
    private List<QuestionTemplate> getQuestionTemplates(List<QuestionBase> questionBases,QuestionSourceEnum questionSource) {
        List<QuestionTemplate> list = new ArrayList<>();
        for (QuestionBase  questionBase : questionBases) {
            QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.fromCode(questionBase.getQuestionType());
            QuestionBase question = questionBase;
            if(questionSource == QuestionSourceEnum.DB) {
                question = selectQuestionBody(questionBase, BigDecimal.ZERO, AnswerShowTypeEnum.True.getCode(), null, null, "");
            }
            switch (questionTypeEnum){
                case SingleChoice:
                case MultipleChoice:
                case IMAGE:
                    List<QuestionTemplate> resultChoice = getChoiceQuestionTemplates(question);
                    list.addAll(resultChoice);
                    break;
                case GapFilling:
                case Explain:
                case ShortAnswer:
                case Analysis:
                case Discuss:
                    List<QuestionTemplate> resultSbjective = getSbjectiveQuestionTemplates(question);
                    list.addAll(resultSbjective);
                    break;
                case B1:
                    List<QuestionTemplate> resultB1 = getB1QuestionTemplates(question);
                    list.addAll(resultB1);
                    break;
                case A3A4Single:
                case A3A4Multiple:
                    List<QuestionTemplate> resultA3A4 = getA3A4QuestionTemplates(question);
                    list.addAll(resultA3A4);
                    break;
                case TrueFalse:
                    List<QuestionTemplate> resultTF = getTFQuestionTemplates(question);
                    list.addAll(resultTF);
                    break;
            }
        }
        return list;
    }

    /**
     * 处理选择题导出
     * @param question
     * @return
     */
    private List<QuestionTemplate> getChoiceQuestionTemplates(QuestionBase question) {
        List<QuestionTemplate> list = new ArrayList<>();
        if(StringUtils.isNotNull(question)){
            QuestionChoiceBody body = (QuestionChoiceBody)question;
            QuestionTemplate template = new QuestionTemplate();
            BeanUtils.copyProperties(body, template);
            String answer = body.getOptions().stream().filter(option -> option.getAnswerFlag()).map(option->option.getSeqCode()).collect(Collectors.joining(""));
            //是否是考生答题
            if(body.getIsExaminee()){
                template.setAnswer(body.getAnswer());
                template.setScore(body.getScore());
                template.setExamineeScore(body.getExamineeScore());
                template.setExamineeAnswer(answer);
                template.setCorrect(body.getCorrect());
            }else {
                template.setAnswer(answer);
            }
            template.setQuestionType(QuestionTypeEnum.fromCode(question.getQuestionType()).getName());
            list.add(template);
            for(QuestionOption option:body.getOptions()){
                template = new QuestionTemplate();
                template.setTitle(option.getContent());
                template.setAnswer(option.getSeqCode());
                list.add(template);
            }
        }
        return list;
    }

    /**
     * 处理主观题导出
     * @param question
     * @return
     */
    private List<QuestionTemplate> getSbjectiveQuestionTemplates(QuestionBase question) {
        List<QuestionTemplate> list = new ArrayList<>();
        if(StringUtils.isNotNull(question)){
            QuestionAnswerBody body= (QuestionAnswerBody)question;
            QuestionTemplate template = new QuestionTemplate();
            BeanUtils.copyProperties(body, template);
            template.setQuestionType(QuestionTypeEnum.fromCode(question.getQuestionType()).getName());
            list.add(template);
            for(QuestionAnswer answer:body.getAnswers()){
                template = new QuestionTemplate();
                template.setTitle(answer.getSeqCode());
                template.setAnswer(answer.getAnswer());
                template.setScore(answer.getScore());
                template.setExamineeScore(answer.getExamineeScore());
                template.setExamineeAnswer(answer.getExamineeAnswer());
                template.setCorrect(answer.getCorrect());
                list.add(template);
            }
        }
        return list;
    }

    /**
     * 处理主观题导出
     * @param question
     * @return
     */
    private List<QuestionTemplate> getB1QuestionTemplates(QuestionBase question) {
        List<QuestionTemplate> list = new ArrayList<>();
        if(StringUtils.isNotNull(question)){
            QuestionB1Body body= (QuestionB1Body)question;
            QuestionTemplate template = new QuestionTemplate();
            BeanUtils.copyProperties(body, template);
            template.setQuestionType(QuestionTypeEnum.fromCode(question.getQuestionType()).getName());

            int i = 0;
            for(B1Option b1Option:body.getOptions()){
                if(i==0){
                    i++;
                    template.setTitle(b1Option.getContent());
                    template.setAnswer(b1Option.getSeqCode());
                    list.add(template);
                }else {
                    template = new QuestionTemplate();
                    template.setTitle(b1Option.getContent());
                    template.setAnswer(b1Option.getSeqCode());
                    list.add(template);
                }
            }

            for(B1Choice b1Choice:body.getChoices()){
                template = new QuestionTemplate();
                template.setQuestionType(i+"");
                template.setTitle(b1Choice.getTitle());
                template.setAnswer(b1Choice.getAnswer());
                template.setExplain(b1Choice.getExplain());
                template.setScore(b1Choice.getScore());
                template.setExamineeScore(b1Choice.getExamineeScore());
                template.setExamineeAnswer(b1Choice.getExamineeAnswer());
                template.setCorrect(b1Choice.getCorrect());
                list.add(template);
                i++;
            }
        }
        return list;
    }

    /**
     * 处理A3A4导出
     * @param question
     * @return
     */
    private List<QuestionTemplate> getA3A4QuestionTemplates(QuestionBase question) {
        List<QuestionTemplate> list = new ArrayList<>();
        if(StringUtils.isNotNull(question)){
            QuestionA3A4Body body= (QuestionA3A4Body)question;
            QuestionTemplate template = new QuestionTemplate();
            BeanUtils.copyProperties(body, template);
            template.setQuestionType(QuestionTypeEnum.fromCode(question.getQuestionType()).getName());
            list.add(template);
            int i = 1;
            for(QuestionChoice questionChoice:body.getQuestions()){
                template = new QuestionTemplate();
                template.setQuestionType(i+"");
                template.setTitle(questionChoice.getTitle());
                template.setExplain(questionChoice.getExplain());
                String answer = questionChoice.getOptions().stream().filter(option -> option.getAnswerFlag()).map(option->option.getSeqCode()).collect(Collectors.joining(""));
                //是否是考生答题
                if(body.getIsExaminee()){
                    //标注答案
                    template.setAnswer(questionChoice.getAnswer());
                    template.setExamineeAnswer(answer);
                    template.setScore(questionChoice.getScore());
                    template.setExamineeScore(questionChoice.getExamineeScore());
                    template.setCorrect(questionChoice.getCorrect());
                }else {
                    template.setAnswer(answer);
                }
                list.add(template);
                i++;
                for(QuestionOption option:questionChoice.getOptions()){
                    template = new QuestionTemplate();
                    template.setTitle(option.getContent());
                    template.setAnswer(option.getSeqCode());
                    list.add(template);
                }
            }
        }
        return list;
    }

    /**
     * 处理判断题导出
     * @param question
     * @return
     */
    private List<QuestionTemplate> getTFQuestionTemplates(QuestionBase question) {
        List<QuestionTemplate> list = new ArrayList<>();
        if(StringUtils.isNotNull(question)){
            QuestionTFBody body= (QuestionTFBody)question;
            QuestionTemplate template = new QuestionTemplate();
            BeanUtils.copyProperties(body, template);
            template.setQuestionType(QuestionTypeEnum.fromCode(question.getQuestionType()).getName());
            //是否是考生答题
            if(body.getIsExaminee()){
                template.setExamineeAnswer("1".equals(body.getAnswerFlag())?ExamConstants.QUESTION_TRUE:ExamConstants.QUESTION_FALSE);
                template.setExamineeScore(body.getExamineeScore());
            }
            list.add(template);
        }
        return list;
    }

    /**
     * 生成word内容
     *
     * @param questions
     * @param response
     */
    private void createWord(HttpServletResponse response,List<QuestionTemplate> questions) {
        Documents.DocumentBuilder of = Documents.of();
        Map<String, Object> allData = new HashMap<>();
        int[] array = IntStream.range(0, questions.size())
                .filter(i -> questions.get(i).getRepoName() != null).toArray();
        AtomicInteger questionNo = new AtomicInteger();
        for (int i = 0; i < array.length; i++) {
            try {
                int fromIndex = array[i];
                int toIndex = i<array.length-1?array[i+1]:questions.size();
                List<QuestionTemplate> templates = questions.subList(fromIndex,toIndex);
                Map<String, Object> datas = PoitlUtil.createQuestion(of, templates, questionNo, ImportQuestionTypeEnum.试题,false,true);
                allData.putAll(datas);
            } catch (Exception e) {
                log.error("导出word:", e);
                throw new ServiceException("导出word:" + e.getMessage());
            }
        }
        DocumentRenderData data = of.create();
        XWPFTemplate template = XWPFTemplate.create(data);
        try {
            // 本地资源路径
            String localPath = EightConfig.getProfile();
            String dirPath = localPath+File.separator + DateUtils.dateTime();
            Path directory = Paths.get(dirPath);
            if (!Files.exists(directory)) {
                Files.createDirectories(directory);
            }
            String docPath = dirPath + File.separator + String.format("%s.doc", UUID.randomUUID());
            template.writeToFile(docPath);
            //渲染图片处理
            XWPFTemplate templateRender = XWPFTemplate.compile(docPath);
            templateRender.render(allData);
            OutputStream out = response.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(out);
            templateRender.write(bos);
            bos.flush();
            out.flush();
            PoitlIOUtils.closeQuietlyMulti(templateRender, bos, out);
            //todo 清空临时word临时文件
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出word", e);
        }
    }

    /**
     * 生成pdf内容
     *
     * @param questions
     * @param response
     */
    private void createPdf(HttpServletResponse response,List<QuestionTemplate> questions) {
        List<String> pdfQuestions = new ArrayList<>();
        int[] array = IntStream.range(0, questions.size())
                .filter(i -> questions.get(i).getRepoName() != null).toArray();
        AtomicInteger questionNo = new AtomicInteger();
        for (int i = 0; i < array.length; i++) {
            try {
                int fromIndex = array[i];
                int toIndex = i<array.length-1?array[i+1]:questions.size();
                List<QuestionTemplate> templates = questions.subList(fromIndex,toIndex);
                PdfUtil.createQuestion(pdfQuestions,templates, questionNo);
            } catch (Exception e) {
                log.error("导出pdf:", e);
                throw new ServiceException("导出pdf:" + e.getMessage());
            }
        }
        try {
            Map<String, Object> data = new HashMap<>();
            data.put("questions", pdfQuestions);
            byte[] export = PdfFreemarkerUtils.export("question.ftl", data);
            OutputStream out = response.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(out);
            bos.write(export);
            bos.flush();
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出pdf", e);
        }
    }

    /**
     * 解析导入试题
     * @param templates
     */
    private void resolveQuestionTemplate(List<QuestionTemplate> templates, Long userId, Long deptId,HashMap<String,Integer> repoIdMap){
        if(templates.size()>0){
            QuestionTemplate template = templates.get(0);
            validateTemplate(template);
            String questionType = template.getQuestionType();
            QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.fromName(questionType);
            if(questionTypeEnum==null){
                throw new ServiceException(questionType+"题型不存在，导入失败");
            }
            Integer repoId = ExamConstants.REPO_ID;
            Integer sectionId = repoIdMap.get(template.getRepoName());
            switch (questionTypeEnum){
                case SingleChoice:
                case MultipleChoice:
                case IMAGE:
                    saveChoice(templates,questionTypeEnum.getCode(),userId,deptId,repoId,sectionId);
                    break;
                case GapFilling:
                case Explain:
                case ShortAnswer:
                case Analysis:
                case Discuss:
                    saveSubjective(templates,questionTypeEnum.getCode(),userId,deptId,repoId,sectionId);
                    break;
                case B1:
                    saveB1(templates,B1.getCode(),userId,deptId,repoId,sectionId);
                    break;
                case A3A4Single:
                case A3A4Multiple:
                    saveA3A4(templates,questionTypeEnum.getCode(),userId,deptId,repoId,sectionId);
                    break;
                case TrueFalse:
                    saveTrueFalse(templates,TrueFalse.getCode(),userId,deptId,repoId,sectionId);
                    break;
            }
        }
    }

    /**
     * 校验模板单行数据信息
     * @param template
     */
    private void validateTemplate(QuestionTemplate template){
        formatTemplate(template);
        if(StringUtils.isBlank(template.getRepoName())||StringUtils.isBlank(template.getQuestionType())||StringUtils.isBlank(template.getTitle())||StringUtils.isBlank(template.getLevel())){
            throw new ServiceException("题库章节、题型、标题、难度不能为空");
        }
    }

    /**
     * 格式化模板单行数据信息
     * @param template
     */
    private void formatTemplate(QuestionTemplate template){
        template.setTitle(template.getTitle()+System.currentTimeMillis());
        template.setRepoName(StringUtils.isBlank(template.getRepoName())?"":template.getRepoName().trim());
        template.setQuestionType(StringUtils.isBlank(template.getQuestionType())?"":template.getQuestionType().trim());
        template.setTitle(StringUtils.isBlank(template.getTitle())?"":template.getTitle().trim());
        template.setAnswer(StringUtils.isBlank(template.getAnswer())?"":template.getAnswer().trim());
        template.setLevel(StringUtils.isBlank(template.getLevel())?"":template.getLevel().trim());
        template.setExplain(StringUtils.isBlank(template.getExplain())?"":template.getExplain().trim());
    }

    /**
     * 保存来自导入模板的试题
     * @param questionBase
     * @param title
     * @param content
     */
    private void saveQuestonByTemplate(QuestionBase questionBase,String title,String content){
        QuestionVersion query = new QuestionVersion();
        query.setContent(content);
        query.setDeptId(questionBase.getDeptId());
        Integer countAll=questionVersionMapper.selectQuestionVersionList(query).size();
        if(countAll>0){
            throw new ServiceException("题目重复");
        }
        insertQuestionBase(questionBase);
        insertQuestionVersion(questionBase,title,content);
    }

    /**
     * 处理选择题：单选题、多选题
     * @param templates
     * @param questionType 题型
     * @param userId 创建人
     * @param deptId 创建机构id
     * @param repoId 题库id
     * @param sectionId 章节id
     */
    private void saveChoice(List<QuestionTemplate> templates, String questionType, Long userId,Long deptId,Integer
            repoId, Integer sectionId){
        QuestionTemplate template = templates.get(0);
        QuestionChoiceBody questionChoiceBody = new QuestionChoiceBody();
        BeanUtils.copyProperties(template, questionChoiceBody);
        questionChoiceBody.setQuestionType(questionType);
        questionChoiceBody.setCreateBy(userId.toString());
        questionChoiceBody.setUpdateBy(userId.toString());
        questionChoiceBody.setDeptId(deptId.intValue());
        questionChoiceBody.setRepoId(repoId);
        questionChoiceBody.setSectionId(sectionId);
        questionChoiceBody.setLevel(Integer.parseInt(template.getLevel()));

        List<QuestionOption> options = new ArrayList<>();
        for(int i=1;i<templates.size();i++){
            QuestionTemplate templateOption = templates.get(i);
            QuestionOption option = new QuestionOption();
            option.setContent(templateOption.getTitle().trim());
            String answer = template.getAnswer().trim().toUpperCase();
            option.setSeqCode(templateOption.getAnswer().trim().toUpperCase());
            if (answer.length() > 0 && answer.contains(templateOption.getAnswer().trim().toUpperCase())) {
                option.setAnswerFlag(true);
            } else {
                option.setAnswerFlag(false);
            }
            options.add(option);
        }
        questionChoiceBody.setOptions(options);
        saveQuestonByTemplate(questionChoiceBody,questionChoiceBody.getTitle(),JSONObject.toJSONString(questionChoiceBody));
    }

    /**
     * 处理主观题：填空题;名词解释;简答题;分析题;论述题
     * @param templates
     * @param questionType 题型
     * @param userId 创建人
     * @param deptId 创建机构id
     * @param repoId 题库id
     * @param sectionId 章节id
     */
    private void saveSubjective(List<QuestionTemplate> templates, String questionType, Long userId,Long deptId,Integer
            repoId, Integer sectionId){
        QuestionTemplate template = templates.get(0);
        QuestionAnswerBody questionAnswerBody = new QuestionAnswerBody();
        BeanUtils.copyProperties(template, questionAnswerBody);
        questionAnswerBody.setQuestionType(questionType);
        questionAnswerBody.setCreateBy(userId.toString());
        questionAnswerBody.setUpdateBy(userId.toString());
        questionAnswerBody.setDeptId(deptId.intValue());
        questionAnswerBody.setRepoId(repoId);
        questionAnswerBody.setSectionId(sectionId);
        questionAnswerBody.setLevel(Integer.parseInt(template.getLevel()));

        List<QuestionAnswer> answers = new ArrayList<>();
        for(int i=1;i<templates.size();i++){
            QuestionTemplate templateOption = templates.get(i);
            QuestionAnswer answer = new QuestionAnswer();
            answer.setSeqCode(i+"");
            answer.setAnswer(templateOption.getAnswer().trim());
            answers.add(answer);
        }
        questionAnswerBody.setAnswers(answers);
        saveQuestonByTemplate(questionAnswerBody,questionAnswerBody.getTitle(),JSONObject.toJSONString(questionAnswerBody));
    }

    /**
     * 处理主观题：填空题;名词解释;简答题;分析题;论述题
     * @param templates
     * @param questionType 题型
     * @param userId 创建人
     * @param deptId 创建机构id
     * @param repoId 题库id
     * @param sectionId 章节id
     */
    private void saveB1(List<QuestionTemplate> templates, String questionType, Long userId,Long deptId,Integer
            repoId, Integer sectionId){
        QuestionTemplate template = templates.get(0);
        QuestionB1Body questionB1Body = new QuestionB1Body();
        BeanUtils.copyProperties(template, questionB1Body);
        questionB1Body.setQuestionType(questionType);
        questionB1Body.setCreateBy(userId.toString());
        questionB1Body.setUpdateBy(userId.toString());
        questionB1Body.setDeptId(deptId.intValue());
        questionB1Body.setRepoId(repoId);
        questionB1Body.setSectionId(sectionId);
        questionB1Body.setLevel(Integer.parseInt(template.getLevel()));

        List<B1Option> options = new ArrayList<>();
        List<B1Choice> choices = new ArrayList<>();
        String tilte = "";
        for(int i=0;i<templates.size();i++){
            QuestionTemplate templateOption = templates.get(i);
            if(StringUtils.isEmpty(templateOption.getQuestionType())||i==0){
                B1Option option = new B1Option();
                option.setSeqCode(templateOption.getAnswer().trim().toUpperCase());
                option.setContent(templateOption.getTitle().trim());
                options.add(option);
                String optionInfo = String.format("%s、%s",option.getSeqCode(),option.getContent());
                tilte = tilte.length()==0?optionInfo:tilte+" "+optionInfo;
            }else {
                B1Choice b1Choice = new B1Choice();
                b1Choice.setTitle(templateOption.getTitle().trim());
                b1Choice.setExplain(templateOption.getExplain().trim());
                b1Choice.setAnswer(templateOption.getAnswer().trim());
                choices.add(b1Choice);
            }
        }
        questionB1Body.setTitle(tilte);
        questionB1Body.setOptions(options);
        questionB1Body.setChoices(choices);
        saveQuestonByTemplate(questionB1Body,questionB1Body.getTitle(),JSONObject.toJSONString(questionB1Body));
    }
    /**
     * 处理A3A4题：单选题、多选题
     * @param templates
     * @param questionType 题型
     * @param userId 创建人
     * @param deptId 创建机构id
     * @param repoId 题库id
     * @param sectionId 章节id
     */
    private void saveA3A4(List<QuestionTemplate> templates, String questionType, Long userId,Long deptId,Integer
            repoId, Integer sectionId){
        QuestionTemplate template = templates.get(0);
        QuestionA3A4Body questionA3A4Body = new QuestionA3A4Body();
        BeanUtils.copyProperties(template, questionA3A4Body);
        questionA3A4Body.setQuestionType(questionType);
        questionA3A4Body.setCreateBy(userId.toString());
        questionA3A4Body.setUpdateBy(userId.toString());
        questionA3A4Body.setDeptId(deptId.intValue());
        questionA3A4Body.setRepoId(repoId);
        questionA3A4Body.setSectionId(sectionId);
        questionA3A4Body.setLevel(Integer.parseInt(template.getLevel()));

        List<QuestionChoice> questions = new ArrayList<>();
        int[] array = IntStream.range(1, templates.size())
                .filter(i -> (StringUtils.isNotEmpty(templates.get(i).getQuestionType()))).toArray();
        for(int i=0;i<array.length;i++){
            int fromIndex = array[i];
            int toIndex = i<array.length-1?array[i+1]:templates.size();
            List<QuestionTemplate> templateOptions = templates.subList(fromIndex,toIndex);
            QuestionChoice questionChoice = new QuestionChoice();
            List<QuestionOption> options = new ArrayList<>();
            String answer = "";
            for(int j=0;j<templateOptions.size();j++){
                QuestionTemplate templateOption = templateOptions.get(j);
                if(StringUtils.isNotBlank(templateOption.getQuestionType())){
                    questionChoice.setTitle(templateOption.getTitle().trim());
                    questionChoice.setExplain(templateOption.getExplain().trim());
                    answer = templateOption.getAnswer().trim().toUpperCase();
                }else {
                    QuestionOption questionOption = new QuestionOption();
                    questionOption.setContent(templateOption.getTitle());
                    questionOption.setSeqCode(templateOption.getAnswer());
                    if (answer.length() > 0 && answer.contains(templateOption.getAnswer().trim().toUpperCase())) {
                        questionOption.setAnswerFlag(true);
                    } else {
                        questionOption.setAnswerFlag(false);
                    }
                    options.add(questionOption);
                }
            }
            questionChoice.setOptions(options);
            questions.add(questionChoice);
        }
        questionA3A4Body.setQuestions(questions);
        saveQuestonByTemplate(questionA3A4Body,questionA3A4Body.getTitle(),JSONObject.toJSONString(questionA3A4Body));
    }

    /**
     * 处理判断题
     * @param templates
     * @param questionType 题型
     * @param userId 创建人
     * @param deptId 创建机构id
     * @param repoId 题库id
     * @param sectionId 章节id
     */
    private void saveTrueFalse(List<QuestionTemplate> templates, String questionType, Long userId, Long deptId, Integer repoId, Integer sectionId) {
        QuestionTemplate template = templates.get(0);
        QuestionTFBody questionTFBody = new QuestionTFBody();
        BeanUtils.copyProperties(template, questionTFBody);
        questionTFBody.setQuestionType(questionType);
        questionTFBody.setCreateBy(userId.toString());
        questionTFBody.setUpdateBy(userId.toString());
        questionTFBody.setDeptId(deptId.intValue());
        questionTFBody.setRepoId(repoId);
        questionTFBody.setSectionId(sectionId);
        questionTFBody.setLevel(Integer.parseInt(template.getLevel()));
        String answer = StringUtils.isBlank(template.getAnswer())?"":template.getAnswer().trim();
        if (ExamConstants.QUESTION_TRUE.equals(answer)) {
            questionTFBody.setAnswerFlag("1");
        } else if(ExamConstants.QUESTION_FALSE.equals(answer)) {
            questionTFBody.setAnswerFlag("0");
        }else {
            throw new ServiceException(String.format("判断题答案应维护为'%s'或'%s'",ExamConstants.QUESTION_TRUE,ExamConstants.QUESTION_FALSE));
        }
        saveQuestonByTemplate(questionTFBody,questionTFBody.getTitle(),JSONObject.toJSONString(questionTFBody));
    }

    /**
     * 项目启动时，初始化数据到缓存
     */
    @PostConstruct
    public void init()
    {
        loadingQuestionSumCache();
    }

    private void loadingQuestionSumCache() {
    }
}
